package zhuzx.obsolete;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.zhuzx.util.ExcelUtil;
import org.zhuzx.util.GeneralUtil;
import org.zhuzx.util.UnifiedConstants;

public class Resolver {
	
	private static final int THREAD_NUM = 4;
	private Sheet sheet;
	
	public Resolver(Sheet sheet) {
		this.sheet = sheet;
	}
	
	/**
	 * 将sheet按线程数量瓜分，每个线程解析其中一段数据，线程池会统一返回解析结果。
	 * @param cla 具体的解析器实现。
	 * @param er 外围类的实例，用来在此基础上创建内部类（解析器）实例。
	 * @return 按序排列的结果集。注意，若想删除结果集中的元素，必须手动获取迭代器进行迭代。
	 */
	@Deprecated//改成静态内部类，改存储容器。
	public LinkedHashSet<Object> resolve(Resolver er, Class<? extends ParallelExecutor> cla) throws Exception {
		LinkedHashSet<ParallelExecutor> tasks = new LinkedHashSet<ParallelExecutor>(THREAD_NUM);
		int interval = sheet.getLastRowNum()/THREAD_NUM + 1;
		//构造内部类实例必须传入外围类的类型信息和具体实例。这里只是为了代码管理方便，并没有必须使用内部类的需要。
		Constructor<? extends ParallelExecutor> cons =
				cla.getConstructor(Resolver.class, Sheet.class, int.class, int.class);
		for (int i=0; i<THREAD_NUM; i++) {
			int startRow = interval*i;
			int endRow = interval*(i+1);
			if (i == THREAD_NUM-1) {
				//getLastRowNum方法返回的值是最后一行的行索引号，所以需要+1
				endRow = sheet.getLastRowNum() + 1;
			}
			ParallelExecutor pe = cons.newInstance(er, sheet, startRow, endRow);
			tasks.add(pe);
		}
		ExecutorService pool = Executors.newFixedThreadPool(THREAD_NUM);
		List<Future<Collection<?>>> futures = pool.invokeAll(tasks);
		pool.shutdown();
		LinkedHashSet<Object> result = new LinkedHashSet<Object>(sheet.getLastRowNum() + 1);
		for (Future<Collection<?>> fu : futures) {
			result.addAll(fu.get());
		}
		return result;
	}
	
	/**
	 * 解析器的基类，必须继承这个类，实现其call方法作为具体的解析方法。<br>
	 * 其子类的类型信息作为参数传入resolve方法，resolve方法再根据具体的解析器提交任务给线程池。
	 */
	public abstract class ParallelExecutor implements Callable<Collection<?>> {
		protected Sheet sheet;
		protected int startRow;
		protected int endRow;
		
		public ParallelExecutor(Sheet sheet, int startRow, int endRow) {
			this.sheet = sheet;
			this.startRow = startRow;
			this.endRow = endRow;
		}

		/**
		 * 由于每一个循环的endRow等于下一个循环的startRow，注意不要重复读取边界。
		 */
		public abstract Collection<?> call() throws Exception;
		
	}
	
	/**
	 * 简单示例：读取第一列的全部单元格，可以通过增加打印语句，观察读取顺序以验证并发。
	 */
	public class DemoExecutor extends ParallelExecutor {

		public DemoExecutor(Sheet sheet, int startRow, int endRow) {
			super(sheet, startRow, endRow);
		}

		@SuppressWarnings("deprecation")
		public Collection<String> call() {
			LinkedHashSet<String> set = new LinkedHashSet<String>(endRow - startRow);
			for (int i=startRow; i<endRow; i++) {
				Row row = sheet.getRow(i);
				if (row == null) continue;
				Cell cell = row.getCell(0);
				if (cell == null) continue;
				String value = (cell.getCellType() == CellType.NUMERIC) ?
						String.valueOf(cell.getNumericCellValue()) : cell.getStringCellValue();
				set.add(value);
			}
			return set;
		}
	}
	
	public static void main(String[] a) {
		try {
			String file = "C:/Users/zhuzx/Desktop/结算司机处罚汇总数据【12.18-12.24周期】.xls";
			InputStream fis = new FileInputStream(new File(file));
			Workbook wb = file.endsWith(".xls") ? new HSSFWorkbook(fis) : new XSSFWorkbook(fis);
			System.out.println(">>>>解析开始");
			List<Map<String,String>> list = ExcelUtil.createListMapSSFromExcelSheet(wb.getSheetAt(0));
			correctDateTypeFromExcel(list, "周期开始", "周期结束");
			System.out.println(list.get(1));
			wb.close();
			fis.close();
			System.out.println(">>>>解析结束");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void retainDecimalDigits(List<Map<String,String>> list, int digits, String... fields) {
		for (Map<String,String> row : list) {
			for (String field : fields) {
				if (!GeneralUtil.isBlank(row.get(field))) {
					String value = row.get(field);
					int index = value.lastIndexOf(".");
					if (index >= 0) {
						index += digits+1;
						index = Math.min(index, value.length());
						row.put(field, value.substring(0, index));
					}
				}
			}
		}
	}
	
	public static void correctDateTypeFromExcel(List<Map<String,String>> list, String... fields) {
		for (Map<String, String> map : list) {
			for (String field : fields) {
				String value = map.get(field);
				if (value.matches("^[\\d.]+$")) {
					int index = value.lastIndexOf(".");
					if (index >= 0) {
						value = value.substring(0, index);
					}
					if (value.length() > 5) {
						value = new Timestamp(Long.parseLong(value)).toString().substring(0, 19);
					} else {
						value = UnifiedConstants.getDateDaf().format(GeneralUtil.getCalculatedDate(
								new GregorianCalendar(1900,0,-1).getTime(),
								Calendar.DAY_OF_YEAR, Integer.parseInt(value)));
					}
					map.put(field, value);
				}
			}
		}
	}
	
}